---
id: application
title: OutstationApplication Interface
sidebar_label: OutstationApplication
slug: /api/outstation/application
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

The `OutstationApplication` interface provides callbacks for dynamic events and information that the outstation requires from your application:

* Internal Indication (IIN) bits
* Processing requests to WRITE the time
* Processing counter freeze requests
* Persisting changes to analog dead-bands
* Validating and persisting WRITE operations to device attributes
* Processing cold and warm restart operations

## ApplicationIin

The outstation will call `OutstationApplication::getApplicationIin()` whenever the system performs a solicited or unsolicited response. It will merge
private IIN bits with the bits returned by the `ApplicationIin` structure, which contains four internal indication bits that you can control:

* `needTime`: Outstation requires time synchronization
* `localControl`: Some output points are in local mode
* `deviceTrouble`: Device-specific bit that indicates the device has a problem
* `configCorrupt`: Device configuration is corrupt

## Time Synchronization

DNP3 has two different procedures for synchronizing the outstation's time: `LAN` and `Non-LAN`. You don't need to worry about which procedure the master uses; both procedures will call `OutstationApplication::writeAbsoluteTime(..)`, with a timestamp representing the number of milliseconds since January 1st, 1970, 00:00:00 UTC.

Outstations that do not support DNP3 time synchronization should return `WriteTimeResult::NOT_SUPPORTED`.  Outstations that receive their time from another
source, such as NTP or IRIG-B, won't typically accept time synchronization requests from DNP3 unless the other time source is unavailable.

Outstations may notify the master that they require time synchronization by setting the `ApplicationIin.needTime` bit. Outstations must clear this bit
immediately in the `writeAbsoluteTime(..)` callback. Otherwise, the master may interpret this as a failure, causing some DNP3 masters to enter an infinite loop of writing the time.

Typically, an outstation will assert this bit periodically, depending on its internal clock accuracy.

## Cold and Warm Restart

DNP3 requires that compliant outstations be capable of performing a full restart, also known as a "cold restart". Because an attacker could abuse this functionality to
perform a denial of service, we recommend that you disable this functionality in most products. Software gateways and translators that run on a server shared with other services should never implement this functionality. Return `RestartDelay` with `RestartDelayType::NOT_SUPPORTED` to
indicate that the operation is not supported so that the timestamp isn't used.

If you must implement this functionality to pass conformance tests or due to customer requirements, callbacks for both cold and warm restart are available. Return
`RestartDelay` with a time estimate of how long the restart will take in seconds or milliseconds. This delay has no practical use for real-world masters, so don't worry too much about the accuracy of this value.

## Freeze Requests

`OutstationApplication` contains two methods related to freezing counters:

* `freezeCountersAll`: This is called when a counter freeze operation is received using the All Points (0x06) qualifier.
* `freezeCountersRange`: This is  called when a counter freeze operation is received using 8-bit (0x00) or 16-bit (0x01) range qualifiers.

A provided reference to a `DatabaseHandle` may be used to copy counters to frozen counters. The `FreezeType` parameter lets you choose between two types of supported freeze operations:

* `IMMEDIATE_FREEZE`: Copy the current value of a counter to the associated frozen counter point.
* `FREEZE_AND_CLEAR`: Copy the current value of a counter to the associated frozen counter point and clear the current value to 0.

## Writing Device Attributes

When defining an attribute, you may specify that it is writable. When the outstation receives a WRITE request containing
an attribute it follows this procedure:

1. If the attribute is has not been defined the outstation returns `IIN2.NO_FUNC_CODE_SUPPORT`.
2. If the attribute is defined, but the value is not of the correct type the outstation returns `IIN.PARAMETER_ERROR`.
3. The outstation then calls the appropriate handler to ask user code to validate and persist the new value. Rust has a single callback method
whereas the bindings have a callback method for each type of attribute. These callbacks may return false to reject the WRITE. For example,
certain attributes may have allowed ranges or discrete values. If the callback method returns `false` the outstation will
respond with `IIN.PARAMETER_ERROR`.
4. Finally, if the handler returned `true` then the outstation will modify the in-memory value and return an empty response
without error indications.

:::note
The example master can `WRITE` the User Defined Location (g0v245) attribute of the example outstation.
:::



